package com.vlefen.springcloud.grpc.grpc;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.grpc.Attributes;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.netty.util.NetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

@Slf4j
public class DiscoveryNameResolver extends NameResolver {
    private final String serviceName;
    private Listener listener;
    private final DiscoveryClient client;

    private static final Set<Runnable> RUNNER_LIST = Sets.newConcurrentHashSet();

    private static final Timer TIMER = new Timer("grpc-name-resolver", true);

    static {
        TIMER.scheduleAtFixedRate(new Task(), 10 * 1000L, 5 * 1000);
    }


    public DiscoveryNameResolver(String serviceName, DiscoveryClient client) {
        this.serviceName = serviceName;
        this.client = client;
    }

    @Override
    public String getServiceAuthority() {
        return serviceName;
    }

    @Override
    public void start(Listener listener) {
        this.listener = listener;
        RUNNER_LIST.add(this::refresh);
        refresh();
    }

    @Override
    public void shutdown() {
        RUNNER_LIST.clear();
    }

    @Override
    public void refresh() {
        List<ServiceInstance> serviceInstances = client.getInstances(serviceName);
        List<EquivalentAddressGroup> servers = Lists.newArrayListWithCapacity(serviceInstances.size());


        serviceInstances.forEach(instance -> {
            try {
                InetSocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getByAddress(NetUtil.createByteArrayFromIpAddressString(instance.getHost())), instance.getPort());
                servers.add(new EquivalentAddressGroup(inetSocketAddress));
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        });
        this.listener.onAddresses(servers, Attributes.EMPTY);
    }

    private static class Task extends TimerTask {
        @Override
        public void run() {

            RUNNER_LIST.forEach(runnable -> {
                try {
                    runnable.run();
                } catch (Throwable throwable) {
                    log.warn("refresh service failed:{}", throwable.getMessage());
                }
            });
        }
    }


}
